<?php
/**
 * 功能：框架入口文件
 * 说明：frame.php
 * 创建日期：2012/7/22
 * 更新日期：
 * 作者：Mirze
 * 补充说明： 
 * 
 */
//记录开始运行时间
$GLOBALS['_beginTime'] = microtime(TRUE);

define('DS', DIRECTORY_SEPARATOR); //DIRECTORY_SEPARATOR 的简写
define('FRAME_PATH', dirname(__FILE__) . DS); //框架目录路径

// 项目名称
//defined('APP_NAME') or define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME'])));

//$defineArray = require('Init/define.php');
//parse_define($defineArray); //define定义

// 载入核心函数库
require("init/function.php");

//载入全局类名文件
global $G_CLASS_FILES;
if (empty($G_CLASS_FILES)){
    require "init/global_class_files.php";
}

class Frame {
	var $c = "Index"; //controller
	var $a = "index"; //action
	var $_app_config = array();

	//应用程序设置
    private static $_ini = array();

	/**  **/
	public function __construct(array $app_config)
	{
		$this->_app_config =$app_config;
		$this->_library_path = FRAME_PATH; //框架library路径
		$this->initDefine();
	}

	/** define  **/
	function initDefine()
	{
		$libPath = $this->_library_path;
		if(! defined('LIB_CORE')) define('LIB_CORE', $libPath . 'core');
		if(! defined('LIB_DB')) define('LIB_DB', $libPath . 'db');
		if(! defined('LIB_EXCEPTION')) define('LIB_EXCEPTION', $libPath . 'exception');
	}

	/**
	 * (功能描述)
	 *
	 * @param 
	 * @return
	 */
	function run()
	{
		 // 获得请求对应的 UDI（统一目的地信息）
		$udi = $this->requestUDI('array');

		$className = "Controller_" . $udi->c;
		$controllerName = strtolower($className) . ".php";
		$controllerDir = $this->_app_config['APP_DIR'] . '/c/' ;
		$controllerFile = $controllerDir .$controllerName;

		require_once(LIB_CORE . "/controller_abstract.php");

		if (!class_exists($className, false)) {
			$this->loadClass($className, $controllerDir);
		}

		$controller = new $className();

		$actionName = "action" . ucfirst($udi->a);
		if(method_exists($controller, $actionName)) {
			 // 如果指定动作存在，则调用
			 $response = $controller->$actionName();
		 } else {
			 echo "action access fail.";exit;
		 }

		dump($this);
	}

	/**
	 * (功能描述) 返回当前请求对应的 UDI
	 *
	 * 将当前请求中包含的控制器、动作提取出来，构造为一个 UDI。
	 *
	 * @param 
	 * @return
	 */
	public function requestUDI()
	{
		$udi = $this->normalizeUDI();
		$this->c = $udi['c'];
		$this->a = $udi['a'];
		return $this;
	}

	/**
	 * (功能描述) 返回规范化以后的 UDI 数组
	 *
	 * @param 
	 * @return
	 */
	function normalizeUDI()
	{
		 // 从 $_GET 中提取请求参数
        $keys = array_keys($_GET);
        if (!empty($keys))
        {
            $keys = array_combine($keys, $keys);
            $keys = array_change_key_case($keys);
        }

		$udi['c'] = (isset($keys['c'])) ? $_GET[$keys['c']] : $this->c;
        $udi['a'] = (isset($keys['a'])) ? $_GET[$keys['a']] : $this->a;

		return $udi;
	}

	/**
	 * (功能描述)  对字符串或数组进行格式化，返回格式化后的数组
     *
     * $input 参数如果是字符串，则首先以“,”为分隔符，将字符串转换为一个数组。
     * 接下来对数组中每一个项目使用 trim() 方法去掉首尾的空白字符。最后过滤掉空字符串项目。
     *
     * 该方法的主要用途是将诸如：“item1, item2, item3” 这样的字符串转换为数组。
     *
     * @code php
     * $input = 'item1, item2, item3';
     * $output = Frame::normalize($input);
     * // $output 现在是一个数组，结果如下：
     * // $output = array(
     * //   'item1',
     * //   'item2',
     * //   'item3',
     * // );
     *
     * $input = 'item1|item2|item3';
     * // 指定使用什么字符作为分割符
     * $output = Frame::normalize($input, '|');
     * @endcode
     *
     * @param array|string $input 要格式化的字符串或数组
     * @param string $delimiter 按照什么字符进行分割
     * @return array 格式化结果
     */
    static function normalize($input, $delimiter = ',')
    {
        if (!is_array($input)) {
            $input = explode($delimiter, $input);
        }
        $input = array_map('trim', $input);
        return array_filter($input, 'strlen');
    }

	/**
	 * (功能描述)  获取指定的设置内容
	 * 
	 * $option 参数指定要获取的设置名。
     * 如果设置中找不到指定的选项，则返回由 $default 参数指定的值。
     *
     * @code php
     * $option_value = Frame::ini('my_option');
     * @endcode
	 *
	 * 对于层次化的设置信息，可以通过在 $option 中使用“/”符号来指定。
     *
     * 例如有一个名为 option_group 的设置项，其中包含三个子项目。
     * 现在要查询其中的 my_option 设置项的内容。
     *
     * @code php
     * // +--- option_group
     * //   +-- my_option  = this is my_option
     * //   +-- my_option2 = this is my_option2
     * //   \-- my_option3 = this is my_option3
     *
     * // 查询 option_group 设置组里面的 my_option 项
     * // 将会显示 this is my_option
     * echo Frame::ini('option_group/my_option');
     * @endcode
     *
     * 要读取更深层次的设置项，可以使用更多的“/”符号，但太多层次会导致读取速度变慢。
     *
     * 如果要获得所有设置项的内容，将 $option 参数指定为 '/' 即可：
     *
     * @code php
     * // 获取所有设置项的内容
     * $all = Frame::ini('/');
     * @endcode
     *
     * @param string $option 要获取设置项的名称
     * @param mixed $default 当设置不存在时要返回的设置默认值
     * @return mixed 返回设置项的值
	 */
    static function ini($option, $default = null)
    {
        if ($option == '/') return self::$_ini;

        if (strpos($option, '/') === false) {
            return array_key_exists($option, self::$_ini) ? self::$_ini[$option] : $default;
        }

        $parts = explode('/', $option);
        $pos =& self::$_ini;
        foreach ($parts as $part) {
            if (!isset($pos[$part])) return $default;
            $pos =& $pos[$part];
        }
        return $pos;
    }

	/**
	 * (功能描述)
	 *
	 * @param 
	 * @return
	 */
	static function autoload($className)
	{
		self::loadClass($className, null, false);
	}

	/**
	 * (功能描述)
	 *
	 * @param 
	 * @return
	 */
	static function loadClass($className, $dirs = null, $throw = true)
	{
		 if (class_exists($className, false) || interface_exists($className, false)) {
            return $className;
        }

		global $G_CLASS_FILES;
		$classNameLower = strtolower($className);
        if (isset($G_CLASS_FILES[$classNameLower])) {
            require $G_CLASS_FILES[$classNameLower];
            return $classNameLower;
        }

		if(!empty($dirs) && !is_array($dirs)) {
			$path = $dirs . DS . strtolower($className) . '.php';
		} else {
		    $path = strtolower($className) . '.php';
		}
		require $path;

		if (!class_exists($className, false) && ! interface_exists($className, false)) {
			$msg = sprintf('Class "%s" declare file "%s" ', $className, $path);
			throw new FException($msg);
			return false;
		}
		return $className;
	}
	
	 /**
     * 注册或取消注册一个自动类载入方法
     *
     * 该方法参考 Zend Framework。
     *
     * @param string $class 提供自动载入服务的类
     * @param boolean $enabled 启用或禁用该服务
     */
    static function registerAutoload($class = 'Frame', $enabled = true)
    {
    	
        if (!function_exists('spl_autoload_register')) {
            require_once FRAME_PATH . 'exception/fexception.class.php';
            throw new FException('spl_autoload does not exist in this PHP installation');
        }

        if ($enabled === true) {
            spl_autoload_register(array($class, 'autoload'));
        } else {
            spl_autoload_unregister(array($class, 'autoload'));
        }
    }


}

/** 设置对象的自动载入 **/
Frame::registerAutoload();

?>